package cn.actoncode.boot.framework.common.json;

import cn.actoncode.boot.framework.common.exception.ServerException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.CollectionType;
import lombok.NonNull;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Primary;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

@Primary
@ConditionalOnMissingBean(PlatformJson.class)
public class PlatformJson {

    private static ObjectMapper INSTANCE = new ObjectMapper();

    static {
        //日期格式
        INSTANCE.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //设置时区
        INSTANCE.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 允许属性名称没有引号
        INSTANCE.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // 允许单引号
        INSTANCE.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //序列化-忽略null值的属性
        INSTANCE.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //序列化-允许序列化空对象
        INSTANCE.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //反序列化-忽略在json字符串中存在但在java对象实际没有的属性
        INSTANCE.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule module = new SimpleModule();
        module.addDeserializer(ObjectNode.class, new StdDeserializer<ObjectNode>(ObjectNode.class) {
            @Override
            public ObjectNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                JsonDeserializer<? extends JsonNode> deserializer = JsonNodeDeserializer.getDeserializer(ObjectNode.class);
                try {
                    return (ObjectNode) deserializer.deserialize(p, ctxt);
                } catch (JsonMappingException e) {
                    return null;
                }
            }
        });
        INSTANCE.registerModule(module);
    }

    /**
     * 序列化，将对象转化为json字符串
     *
     * @param data
     * @return
     */
    public static String toJson(Object data) {
        if (null == data) {
            return null;
        }
        try {
            return INSTANCE.writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new ServerException(e);
        }
    }

    /**
     * 反序列化，将json字符串转化为对象
     *
     * @param json
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T parse(@NonNull String json, Class<T> clazz) {
        try {
            return INSTANCE.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new ServerException(e);
        }
    }

    /**
     * 反序列化，将json字符串转化为对象
     *
     * @param json
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> parseArray(@NonNull String json, Class<T> clazz) {
        try {
            CollectionType listType = INSTANCE.getTypeFactory().constructCollectionType(ArrayList.class, clazz);
            return INSTANCE.readValue(json, listType);
        } catch (JsonProcessingException e) {
            throw new ServerException(e);
        }
    }

    /**
     * 反序列化，将ObjectNode转化为对象
     *
     * @param objectNode
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T convert(@NonNull ObjectNode objectNode, Class<T> clazz) {
        return INSTANCE.convertValue(objectNode, clazz);
    }

    /**
     * 创建ObjectNode
     *
     * @return
     */
    public static ObjectNode createObjectNode() {
        return INSTANCE.createObjectNode();
    }
}
